<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    //一，Object.keys(obj)
    let person = {
      name: "张三",
      age: 25,
      address: "深圳",
      getName: function () {}
    };
    console.log(Object.keys(person)); //["name", "age", "address", "getName"]

    //处理数组，返回索引值数组
    let arr = [1, 2, 3, 4, 5, 6];
    console.log(Object.keys(arr)); //["0", "1", "2", "3", "4", "5"]

    //处理字符串，返回索引值数组
    let str = "hello你好";
    console.log(Object.keys(str)); //["0", "1", "2", "3", "4", "5", "6"]

    //获取到属性对应的值，做一些处理
    Object.keys(person).map((key) => {
      console.log(key); //name age address getName
      console.log(person[key]); //张三 25 深圳 ƒ () {}
    })



    //二，Object.values()
    let obj = {
      foo: "bar",
      baz: 20
    };
    console.log(Object.values(obj)); //["bar", 20]

    //属性名为数值的属性，是按照数值大小，从小到大遍历的
    const obj1 = {
      100: "a",
      2: "b",
      7: "c"
    };
    console.log(Object.values(obj1)); //["b", "c", "a"]  

    //Object.values()只会遍历对象自身的可遍历属性  //enumerable: false不可枚举
    const obj2 = Object.create({}, {
      p: {
        value: 10
      }
    });
    console.log(obj2) //{p: 10}
    console.log(Object.values(obj2)) //[]
    console.log(Object.getOwnPropertyDescriptors(obj2)); //{p: {…}}

    //Object.create方法的第二个参数添加的对象属性（属性p）如果不显式声明 默认是不可遍历的
    const obj3 = Object.create({}, {
      p: {
        value: 10,
        enumerable: true,
        configurable: true,
        writable: true,
      }
    })
    console.log(Object.values(obj3)); //[10]

    //Object.values会过滤属性名为 Symbol 值的属性
    Object.values({
      [Symbol()]: 123,
      foo: 'abc'
    });
    console.log(Object.values('foo')) //["f", "o", "o"] //如果Object.values方法的参数是一个字符串，会返回各个字符组成的一个数组。

    //如果参数不是对象，Object.values会先将其转为对象
    console.log(Object.values(42)); // []
    console.log(Object.values(true)); // []
    // console.log(Object.values(undefined)); //error
    // console.log(Object.values(null)); //error

    //三，Object.entries()
    //Object.entries方法返回一个数组，成员是参数对象自身的（不含继承的）所有可遍历（enumerable）属性的键值对数组
    var obj4 = {
      foo: 'bar',
      baz: 42
    };
    console.log(Object.entries(obj4)) //[["foo", "bar"], ["baz", 42]]

    //如果原对象的属性名是一个 Symbol 值，该属性会被省略
    console.log(Object.entries({
      [Symbol()]: 123,
      foo: 'abc'
    })) //["foo", "abc"]

    //遍历对象的属性
    let obj5 = {
      one: 1,
      two: 2,
    }
    console.log(Object.entries(obj5)) // [["one", 1], ["two", 2]]

    for (let [k, v] of Object.entries(obj5)) {
      console.log(`${JSON.stringify(k)} : ${JSON.stringify(v)}`); // "one" : 1  "two" : 2
    }

    //将对象转为真正的Map结构
    const obj6 = {
      foo: "bar",
      baz: 10
    };
    console.log(Object.entries(obj6)) //[["foo", "bar"], ["baz", 10]]
    const map = new Map(Object.entries(obj6));
    console.log(map); // {"foo" => "bar", "baz" => 10} //[[Prototype]]: Map


    
    //实现Object.entries方法
    const entries = (obj) => {
      let result = [];
      const objType = typeof (obj);
      if (obj === undefined || obj === null) {
        throw new TypeError();
      }
      if (objType === "number" || objType === "boolean") {
        return [];
      }
      for (let k of Object.keys(obj)) {
        result.push([k, obj[k]]);
      }
      return result
    }

    console.log(entries(obj6)) //[ ["foo", "bar"], ["baz", 10]]
  </script>
</body>

</html>